using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public static class KeyCounter
{
    public const int KeyCounts = 36;//4+4+6+4+10+8
}

/// <summary>
/// several workable keys in the gameplay
/// </summary>
public enum GameplayKeyCode
{
    S, A, D, W,
    DownArrow, LeftArrow, RightArrow, UpArrow,
    I, O, P, J, K, L,
    Z, X, C, V,
    NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9, NUM0,
    Space, Enter, Escape,
    Shift, Ctrl, Alt,
    BackSpace,
    Tab,
}

public class InputManager : SingletonMonoBehaviour<InputManager>, GameInput.IKeyboardActions
{
    private GameInput _gameInputActions;
    /// <summary>
    /// the phase of the key input
    /// </summary>
    private List<InputActionPhase> _phaseList;
    private List<Action> ON_KeyEvent_Started;
    private List<Action> ON_KeyEvent_Performed;
    private List<Action> ON_KeyEvent_Canceled;

    private Action<Vector2> ON_Vector2_KeyEvent;

    private void Awake()
    {
        INI_Singleton();
        _phaseList = new List<InputActionPhase>();
        ON_KeyEvent_Started = new List<Action>();
        ON_KeyEvent_Performed = new List<Action>();
        ON_KeyEvent_Canceled = new List<Action>();
        ON_Vector2_KeyEvent = delegate (Vector2 vector2) { };//avoid null delegate
        for (int i = 0; i < KeyCounter.KeyCounts; i++)
        {
            _phaseList.Add(new InputActionPhase());
            ON_KeyEvent_Started.Add(delegate { });
            ON_KeyEvent_Performed.Add(delegate { });
            ON_KeyEvent_Canceled.Add(delegate { });
        }

        _gameInputActions = new GameInput();
    }

    private void Start()
    {
        _gameInputActions.Keyboard.SetCallbacks(this);
        _gameInputActions.Keyboard.Enable();
    }

    private void Update()
    {
        for (int i = 0; i < KeyCounter.KeyCounts; i++)
        {
            if (_phaseList[i] == InputActionPhase.Performed) ON_KeyEvent_Performed[i]();
        }
    }

    private void EventHandler(GameplayKeyCode keyCode, InputActionPhase phase)
    {
        _phaseList[(int)keyCode] = phase;
        switch (phase)
        {
            case InputActionPhase.Started:
                ON_KeyEvent_Started[(int)keyCode]();
                break;
            case InputActionPhase.Canceled:
                ON_KeyEvent_Canceled[(int)keyCode]();
                break;
            default:
                break;
        }
    }

    /// <summary>
    /// register or unregister an single key event
    /// </summary>
    /// <param name="keyCode"></param>
    /// <param name="phase"></param>
    /// <param name="action"></param>
    /// <param name="isToCombineEvent"></param>
    public void UpdateInputEvent(GameplayKeyCode keyCode, InputActionPhase phase, Action action, bool isToCombineEvent)
    {
        if (isToCombineEvent)
        {
            switch (phase)
            {
                case InputActionPhase.Started:
                    ON_KeyEvent_Started[(int)keyCode] += action;
                    break;
                case InputActionPhase.Performed:
                    ON_KeyEvent_Performed[(int)keyCode] += action;
                    break;
                case InputActionPhase.Canceled:
                    ON_KeyEvent_Canceled[(int)keyCode] += action;
                    break;
                default:
                    break;
            }
        }
        else
        {
            switch (phase)
            {
                case InputActionPhase.Started:
                    ON_KeyEvent_Started[(int)keyCode] -= action;
                    break;
                case InputActionPhase.Performed:
                    ON_KeyEvent_Performed[(int)keyCode] -= action;
                    break;
                case InputActionPhase.Canceled:
                    ON_KeyEvent_Canceled[(int)keyCode] -= action;
                    break;
                default:
                    break;
            }
        }
    }

    /// <summary>
    /// register or unregister vector event
    /// </summary>
    public void UpdateInputEvent(Action<Vector2> action, bool isToCombineEvent)
    {
        if (isToCombineEvent) { ON_Vector2_KeyEvent += action; }
        else { ON_Vector2_KeyEvent -= action; }
    }

    #region KeyboardInputEvent
    void GameInput.IKeyboardActions.OnK1_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.S, context.phase); }
    void GameInput.IKeyboardActions.OnK1_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.A, context.phase); }
    void GameInput.IKeyboardActions.OnK1_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.D, context.phase); }
    void GameInput.IKeyboardActions.OnK1_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.W, context.phase); }
    void GameInput.IKeyboardActions.OnK2_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.DownArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.LeftArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.RightArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK2_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.UpArrow, context.phase); }
    void GameInput.IKeyboardActions.OnK3_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.I, context.phase); }
    void GameInput.IKeyboardActions.OnK3_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.O, context.phase); }
    void GameInput.IKeyboardActions.OnK3_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.P, context.phase); }
    void GameInput.IKeyboardActions.OnK3_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.J, context.phase); }
    void GameInput.IKeyboardActions.OnK3_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.K, context.phase); }
    void GameInput.IKeyboardActions.OnK3_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.L, context.phase); }
    void GameInput.IKeyboardActions.OnK4_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Z, context.phase); }
    void GameInput.IKeyboardActions.OnK4_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.X, context.phase); }
    void GameInput.IKeyboardActions.OnK4_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.C, context.phase); }
    void GameInput.IKeyboardActions.OnK4_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.V, context.phase); }
    void GameInput.IKeyboardActions.OnK5_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM1, context.phase); }
    void GameInput.IKeyboardActions.OnK5_10(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM0, context.phase); }
    void GameInput.IKeyboardActions.OnK5_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM2, context.phase); }
    void GameInput.IKeyboardActions.OnK5_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM3, context.phase); }
    void GameInput.IKeyboardActions.OnK5_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM4, context.phase); }
    void GameInput.IKeyboardActions.OnK5_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM5, context.phase); }
    void GameInput.IKeyboardActions.OnK5_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM6, context.phase); }
    void GameInput.IKeyboardActions.OnK5_7(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM7, context.phase); }
    void GameInput.IKeyboardActions.OnK5_8(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM8, context.phase); }
    void GameInput.IKeyboardActions.OnK5_9(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.NUM9, context.phase); }
    void GameInput.IKeyboardActions.OnK6_1(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Space, context.phase); }
    void GameInput.IKeyboardActions.OnK6_2(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Enter, context.phase); }
    void GameInput.IKeyboardActions.OnK6_3(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Escape, context.phase); }
    void GameInput.IKeyboardActions.OnK6_4(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Shift, context.phase); }
    void GameInput.IKeyboardActions.OnK6_5(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Ctrl, context.phase); }
    void GameInput.IKeyboardActions.OnK6_6(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Alt, context.phase); }
    void GameInput.IKeyboardActions.OnK6_7(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.BackSpace, context.phase); }
    void GameInput.IKeyboardActions.OnK6_8(InputAction.CallbackContext context) { EventHandler(GameplayKeyCode.Tab, context.phase); }
    void GameInput.IKeyboardActions.OnK_Dir(InputAction.CallbackContext context) { ON_Vector2_KeyEvent(context.ReadValue<Vector2>()); }
    #endregion
}
